package com.TanNgee.remoting.transport.socket;

import com.TanNgee.excpetion.RpcException;
import com.TanNgee.extension.ExtensionLoader;
import com.TanNgee.registry.ServiceDiscovery;
import com.TanNgee.remoting.dto.RpcRequest;
import com.TanNgee.remoting.transport.RpcRequestTransport;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * Socket客户端
 * <p>
 * 客户端主要用于发送网络请求到服务端（目标方法所在的服务器）。
 * 当知道了服务端的地址之后，就可以通过 SocketRpcClient 发送 rpc 请求(RpcRequest) 到服务端了(如果我们要找到服务端的地址
 *
 * @author 陈毅
 * @create 2022/3/20 23:23
 */
@AllArgsConstructor
@Slf4j
public class SocketRpcClient implements RpcRequestTransport {
    // 服务发现类
    private final ServiceDiscovery serviceDiscovery;

    public SocketRpcClient() {
        this.serviceDiscovery = ExtensionLoader.getExtensionLoader(ServiceDiscovery.class).getExtension("zk");
    }

    @Override
    public Object sendRpcRequest(RpcRequest rpcRequest) {
        // 获取服务地址
        InetSocketAddress inetSocketAddress = serviceDiscovery.lookupService(rpcRequest);

        try (Socket socket = new Socket()) {
            // Socket对象通过地址发起Socket连接
            socket.connect(inetSocketAddress);

            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());

            // 正式向服务器发起请求
            objectOutputStream.writeObject(rpcRequest);

            // 服务器发回来的响应
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

            // 读取服务器返回来的请求并return
            return objectInputStream.readObject();

        } catch (IOException | ClassNotFoundException e) {
            throw new RpcException("调用服务失败:", e);
        }
    }
}
